#include "asynclogging.h"

#include <functional>
#include <utility>
#include <memory>

using namespace tiny_muduo;

void AsyncLogging::Append(const char* data, int len) {
  MutexLockGuard guard(mutex_);
  if (current_->writablebytes() >= len) {
    current_->Append(data, len);
  } else {
    buffers_to_write_.emplace_back(std::move(current_)); 
    if (next_) {
      current_ = std::move(next_);
    } else {
      current_.reset(new Buffer());
    }
    cond_.Notify();
  }
}

void AsyncLogging::Flush() {
  fflush(stdout);
}

void AsyncLogging::ThreadFunc() {
  latch_.CountDown();
  BufferPtr newbuffer_current(new Buffer());
  BufferPtr newbuffer_next(new Buffer());
  LogFilePtr log(new LogFile(filepath_));
  newbuffer_current->SetBufferZero();
  newbuffer_next->SetBufferZero();
  BufferVector buffers;


    /*
    双缓冲区技术涉及两个缓冲区：一个前台缓冲区（Front Buffer）和一个后台缓冲区（Back Buffer）。这两个缓冲区通常是内存中的两个连续空间，它们的大小和格式相同。
    当进行数据的显示或写入操作时，系统会交替使用这两个缓冲区。
    数据准备阶段：
    当需要更新显示内容时，系统会在后台缓冲区中进行所有的数据处理和渲染操作。前台缓冲区保持不变，继续显示当前的内容，确保用户看到的是连贯的图像或数据。
    数据交换阶段：
    一旦后台缓冲区的数据处理和渲染完成，系统会将后台缓冲区的内容快速复制到前台缓冲区。这个过程通常由硬件加速完成，非常迅速，因此用户几乎感觉不到任何延迟或卡顿。
    显示更新：
    复制完成后，系统会切换指针，使得下一个周期的数据处理在原来的前台缓冲区（现在是后台）进行，而新的前台缓冲区则显示刚刚复制的数据。
    */

  while (running_) {
    {
      MutexLockGuard guard(mutex_);
      if (buffers_to_write_.empty()) {
        cond_.WaitForFewSeconds(kBufferWriteTimeout);
      }

      buffers_to_write_.emplace_back(std::move(current_));
      buffers.swap(buffers_to_write_);
      current_ = std::move(newbuffer_current);
      if (!next_) {
        next_ = std::move(newbuffer_next);
      }
    }
    
    for (const auto& buffer : buffers) {
      log->Write(buffer->data(), buffer->len());
    }

    if (log->writtenbytes() >= kSingleFileMaximumSize) {
      log.reset(new LogFile(filepath_));
    } 
    
    if (buffers.size() > 2) {
      buffers.resize(2);
    }

    if (!newbuffer_current) {
      newbuffer_current = std::move(buffers.back());
      buffers.pop_back();
      newbuffer_current->SetBufferZero();
    }

    if (!newbuffer_next) {
      newbuffer_current = std::move(buffers.back());
      buffers.pop_back();
      newbuffer_current->SetBufferZero();
    }
    buffers.clear();
  }
}